﻿namespace Scheduler.Library
{
    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Timers;
    using System.Threading.Tasks;

    /// <summary>
    /// 任务调度器
    /// </summary>
    public class SchedulerService : IScheduler
    {
        /// <summary>
        /// 同步锁
        /// </summary>
        private readonly object _syncObject = new object();

        /// <summary>
        /// 任务字典
        /// </summary>
        private readonly OrderedDictionary _tasks;

        /// <summary>
        /// 调度器的状态
        /// </summary>
        public SchedulerStatus _status;

        /// <summary>
        /// 默认构造
        /// </summary>
        public SchedulerService()
        {
            // 初始化任务的容器
            _tasks = new OrderedDictionary();

            // 初始化调度器状态：初始值为已开启任务处理
            _status = SchedulerStatus.Started;
        }

        #region IScheduler接口实现

        /// <summary>
        /// 调度任务
        /// </summary>
        /// <param name="name">任务的名称</param>
        /// <param name="trigger">任务的触发器</param>
        /// <param name="start">是否立即开始任务</param>
        /// <param name="executor">任务内容</param>
        /// <param name="onCompletedAction">完成任务的回调</param>
        public void Schedule(string name, Trigger trigger, Action executor, Action<SchedulerTask> onCompletedAction, bool start = true)
        {
            SchedulerTask task = new SchedulerTask(name, executor, trigger);

            // 设置要调度的任务完成时的回调
            task.OnTaskCompleted = onCompletedAction;

            // 缓存该任务
            lock (_syncObject)
                _tasks.Add(task.Name, task);

            Task.Run(() =>
            {
                // 调度任务
                InternalSchedule(task, start);
            });
        }

        /// <summary>
        /// 是否已经开始调度任务
        /// </summary>
        public bool IsStarted
        {
            get
            {
                lock (_syncObject)
                {
                    return _status == SchedulerStatus.Started;
                }
            }
        }

        /// <summary>
        /// 是否已经停止调度任务
        /// </summary>
        public bool IsShutDown
        {
            get
            {
                lock (_syncObject)
                {
                    return _status == SchedulerStatus.Shutdown;
                }
            }
        }

        /// <summary>
        /// 暂停指定任务运行
        /// </summary>
        /// <param name="name">任务名称</param>
        public void Pause(string name)
        {
            SchedulerTask task = null;

            lock (_syncObject)
            {
                task = _tasks[name] as SchedulerTask;
            }

            Task.Run(() => InternalPause(task));
        }

        /// <summary>
        /// 运行指定任务
        /// </summary>
        /// <param name="name">任务名称</param>
        public void Run(string name)
        {
            SchedulerTask task = null;

            lock (_syncObject)
            {
                task = _tasks[name] as SchedulerTask;
            }
            //if(task.GetStatus().)
            Task.Run(() => InternalRun(task));
        }

        /// <summary>
        /// 恢复指定任务
        /// </summary>
        /// <param name="name">任务名</param>
        public void Resume(string name)
        {
            SchedulerTask task = null;

            lock (_syncObject)
            {
                task = _tasks[name] as SchedulerTask;
            }

            Task.Run(() => InternalResume(task));
        }

        /// <summary>
        /// 删除指定任务
        /// </summary>
        /// <param name="name">任务名</param>
        public void Delete(string name)
        {
            lock (_syncObject)
            {
                InternalDelete(name);
            }
        }

        /// <summary>
        /// 返回任务名称数组.
        /// </summary>
        /// <returns>处理结果</returns>
        public string[] GetTaskNames()
        {
            lock (_syncObject)
            {
                var keyCollection = _tasks.Keys;
                var keys = new string[_tasks.Count];
                keyCollection.CopyTo(keys, 0);
                return keys;
            }
        }

        /// <summary>
        /// 暂停全部任务
        /// </summary>
        public void PauseAll()
        {
            lock (_syncObject)
            {
                InternalPauseAll();
            }
        }

        /// <summary>
        /// 恢复全部任务
        /// </summary>
        public void ResumeAll()
        {
            lock (_syncObject)
            {
                InternalResumeAll();
            }
        }

        /// <summary>
        /// 关闭调度器，所有任务都将暂停
        /// </summary>
        public void ShutDown()
        {
            lock (_syncObject)
            {
                InternalPauseAll();
                _status = SchedulerStatus.Shutdown;
            }
        }

        /// <summary>
        /// 启动调度器
        /// </summary>
        public void StartUp()
        {
            lock (_syncObject)
            {
                InternalResumeAll();
                _status = SchedulerStatus.Started;
            }
        }

        /// <summary>
        /// 获取任务的摘要信息
        /// </summary>
        /// <returns>任务摘要集合</returns>
        public IList<TaskSummary> GetStatus()
        {
            IList<TaskSummary> summaries = new List<TaskSummary>();

            lock (_syncObject)
            {
                Parallel.For(0, _tasks.Count, index =>
                {
                    var summary = ((SchedulerTask)_tasks[index]).GetStatus();
                    lock (summaries) summaries.Add(summary);
                });
            }
            return summaries;
        }

        /// <summary>
        /// 获取指定任务摘要信息
        /// </summary>
        /// <param name="name">任务名称</param>
        /// <returns>任务摘要信息</returns>
        public TaskSummary GetStatus(string name)
        {
            TaskSummary summary = null; // 返回的任务摘要
            SchedulerTask task = null;  // 任务对象

            lock (_syncObject) task = _tasks[name] as SchedulerTask;

            summary = task?.GetStatus();
            return summary;
        }

        #endregion

        #region 内部实现

        /// <summary>
        /// 调度任务
        /// </summary>
        /// <param name="task">要调度的任务</param>
        /// <param name="start">是否立即执行</param>
        private void InternalSchedule(SchedulerTask task, bool start)
        {
            // 如果是手动任务就返回，等待手动启动
            if (task.IsOnDemand) return;

            // 设置任务相关的计时器信息
            Timer timer = new Timer { Interval = task.Trigger.Interval };
            timer.Enabled = true;
            timer.Elapsed += task.OnTimerElapsed;
            task.TaskTimer = timer;

            // 如果标识马上开始，则立即启动计时器，否则的话需要手动开启
            if (start)
                task.TaskTimer.Start();
        }

        /// <summary>
        /// 暂停指定任务
        /// </summary>
        /// <param name="task">要暂定的任务</param>
        private void InternalPause(SchedulerTask task)
        {
            // 判断任务是否可以被暂停
            if (CanPauseOrResume(task))
            {
                task.TaskTimer.Stop();
            }
        }

        /// <summary>
        /// 恢复指定任务
        /// </summary>
        /// <param name="task">要回复的任务</param>
        private void InternalResume(SchedulerTask task)
        {
            if (CanPauseOrResume(task))
            {
                task.TaskTimer.Start();
            }
        }

        /// <summary>
        /// 运行指定任务
        /// </summary>
        ///<param name="task">要运行的任务</param>
        private void InternalRun(SchedulerTask task)
        {
            task?.Run();
        }

        /// <summary>
        /// 删除指定任务
        /// </summary>
        /// <param name="name">任务名称</param>
        private void InternalDelete(string name)
        {
            var task = _tasks[name] as SchedulerTask;
            if (task == null) return;
            if (!task.IsOnDemand)
            {
                task.TaskTimer.Stop();
            }
            _tasks.Remove(name);
        }

        /// <summary>
        /// 恢复所有任务
        /// </summary>
        private void InternalResumeAll()
        {
            Parallel.For(0, _tasks.Count, index =>
            {
                var task = _tasks[index] as SchedulerTask;
                if (CanPauseOrResume(task)) InternalResume(task);
            });
        }

        /// <summary>
        /// 暂停所有任务
        /// </summary>
        private void InternalPauseAll()
        {
            Parallel.For(0, _tasks.Count, index =>
            {
                var task = _tasks[index] as SchedulerTask;
                if (CanPauseOrResume(task)) InternalPause(task);
            });
        }

        /// <summary>
        /// 判断任务是否可以被暂停
        /// </summary>
        /// <param name="task">任务</param>
        /// <returns>判断结果：根据任务是否是点播任务来的，是点播的就不能暂停</returns>
        private bool CanPauseOrResume(SchedulerTask task)
        {
            return task != null && !task.IsOnDemand;
        }

        #endregion
    }
}
